This file is used to analyse the immune cells dataset.

library(dplyr)
library(patchwork)
library(ggplot2)
library(ComplexHeatmap)
library(org.Mm.eg.db)

.libPaths()
## [1] "/usr/local/lib/R/library"

Preparation

In this section, we set the global settings of the analysis. We will store data there :

save_name = "iblmors"
out_dir = "."

We load the dataset :

sobj = readRDS(paste0(out_dir, "/", save_name, "_sobj.rds"))
sobj
## An object of class Seurat 
## 15541 features across 8026 samples within 1 assay 
## Active assay: RNA (15541 features, 2000 variable features)
##  6 dimensional reductions calculated: RNA_pca, RNA_pca_20_tsne, RNA_pca_20_umap, harmony, harmony_20_umap, harmony_20_tsne

We load the sample information :

sample_info = readRDS(paste0(out_dir, "/../1_metadata/wu_sample_info.rds"))
project_names_oi = sample_info$project_name

graphics::pie(rep(1, nrow(sample_info)),
              col = sample_info$color,
              labels = sample_info$project_name)

Here are custom colors for each cell type :

color_markers = readRDS(paste0(out_dir, "/../../1_metadata/hs_hd_color_markers.rds"))

data.frame(cell_type = names(color_markers),
           color = unlist(color_markers)) %>%
  ggplot2::ggplot(., aes(x = cell_type, y = 0, fill = cell_type)) +
  ggplot2::geom_point(pch = 21, size = 5) +
  ggplot2::scale_fill_manual(values = unlist(color_markers), breaks = names(color_markers)) +
  ggplot2::theme_classic() +
  ggplot2::theme(legend.position = "none",
                 axis.line = element_blank(),
                 axis.title = element_blank(),
                 axis.ticks = element_blank(),
                 axis.text.y = element_blank(),
                 axis.text.x = element_text(angle = 30, hjust = 1))

This is the projection of interest :

name2D = "harmony_20_tsne"

We design a custom function to make the GSEA plot and a word cloud graph :

make_gsea_plot = function(gsea_results, gs_oi, fold_change, metric = "FC") {
  fold_change$metric = fold_change[, metric]
  
  plot_list = lapply(gs_oi, FUN = function(gene_set) {
    # Gene set content
    gs_content = gene_sets %>%
      dplyr::filter(gs_name == gene_set) %>%
      dplyr::pull(ensembl_gene) %>%
      unique()
    
    # Gene set size
    nb_genes = length(gs_content)
    
    # Enrichment metrics
    NES = gsea_results@result[gene_set, "NES"]
    p.adjust = gsea_results@result[gene_set, "p.adjust"] %>%
      round(., 4)
    qvalues = gsea_results@result[gene_set, "qvalues"]
    
    if (p.adjust > 0.05) {
      p.adjust = paste0("<span style='color:red;'>", p.adjust, "</span>")
    }
    
    my_subtitle = paste0("\nNES : ", round(NES, 2),
                         " | padj : ", p.adjust,
                         " | qval : ", round(qvalues, 4),
                         " | set size : ", nb_genes, " genes")
    
    # Size limits
    lower_FC = min(fold_change[gs_content, ]$metric, na.rm = TRUE)
    upper_FC = max(fold_change[gs_content, ]$metric, na.rm = TRUE)
    
    # Plot
    p = enrichplot::gseaplot2(x = gsea_results, geneSetID = gene_set) +
      ggplot2::labs(title = gene_set,
                    subtitle = my_subtitle) +
      ggplot2::theme(plot.title = element_text(hjust = 0.5, face = "bold",
                                               margin = ggplot2::margin(3, 3, 5, 3)),
                     plot.subtitle = ggtext::element_markdown(hjust = 0.5,
                                                              size = 10))
    
    wc = ggplot2::ggplot(fold_change[gs_content, ],
                         aes(label = gene_name, size = abs(metric), color = metric)) +
      ggwordcloud::geom_text_wordcloud_area(show.legend = TRUE) +
      ggplot2::scale_color_gradient2(
        name = metric,
        low = aquarius::color_cnv[1],
        mid = "gray70", midpoint = 0,
        high = aquarius::color_cnv[3]) +
      ggplot2::scale_size_area(max_size = 7) +
      ggplot2::theme_minimal() +
      ggplot2::guides(size = "none")
    
    return(list(p, wc))
  }) %>% unlist(., recursive = FALSE)
  
  return(plot_list)
}

Visualization

Gene expression

We visualize gene expression for some markers :

features = c("percent.mt", "percent.rb", "nFeature_RNA")

plot_list = lapply(features, FUN = function(one_gene) {
  Seurat::FeaturePlot(sobj, features = one_gene,
                      reduction = name2D) +
    ggplot2::theme(aspect.ratio = 1) +
    ggplot2::scale_color_gradientn(colors = aquarius::color_gene) +
    Seurat::NoAxes()
})

patchwork::wrap_plots(plot_list, ncol = 3)

Clusters

We visualize clusters :

cluster_plot = Seurat::DimPlot(sobj, reduction = name2D, label = TRUE) +
  Seurat::NoAxes() +
  ggplot2::theme(aspect.ratio = 1)
cluster_plot

Cell type

We visualize cell type split by sample :

plot_list = aquarius::plot_split_dimred(sobj,
                                        reduction = name2D,
                                        split_by = "project_name",
                                        group_by = "cell_type",
                                        split_color = setNames(sample_info$color,
                                                               nm = sample_info$project_name),
                                        group_color = color_markers,
                                        bg_pt_size = 0.5, main_pt_size = 0.5)

plot_list[[length(plot_list) + 1]] = cluster_plot

patchwork::wrap_plots(plot_list, ncol = 4) &
  Seurat::NoLegend()

Cluster type

We summarize major cell type by cluster :

cell_type_clusters = sobj@meta.data[, c("cell_type", "seurat_clusters")] %>%
  table() %>%
  prop.table(., margin = 2) %>%
  apply(., 2, which.max)
cell_type_clusters = setNames(levels(sobj$cell_type)[cell_type_clusters],
                              nm = names(cell_type_clusters))

We define cluster type :

sobj$cluster_type = cell_type_clusters[sobj$seurat_clusters] %>%
  as.factor()
table(sobj$cluster_type, sobj$cell_type)
##      
##       CD4 T cells CD8 T cells Langerhans cells macrophages B cells cuticle
##   IBL           3           0                2           0       6      34
##   ORS           0           2                0           0      16       1
##      
##       cortex medulla  IRS proliferative  IBL  ORS  IFE HFSC melanocytes
##   IBL     58      15   13            12 6344    9  179   52          14
##   ORS      2       0    0             6    1  986   15  109           4
##      
##       sebocytes
##   IBL        33
##   ORS       110

We subset color_markers :

color_markers = color_markers[levels(sobj$cluster_type)]

We compare cluster annotation and cell type annotation :

p1 = Seurat::DimPlot(sobj, group.by = "cell_type",
                     reduction = name2D, cols = color_markers) +
  ggplot2::labs(title = "Cell type") +
  Seurat::NoAxes() +
  ggplot2::theme(aspect.ratio = 1,
                 plot.title = element_text(hjust = 0.5))

p2 = Seurat::DimPlot(sobj, group.by = "cluster_type",
                     reduction = name2D, cols = color_markers) +
  ggplot2::labs(title = "Cluster type") +
  Seurat::NoAxes() +
  ggplot2::theme(aspect.ratio = 1,
                 plot.title = element_text(hjust = 0.5))

patchwork::wrap_plots(p1, p2, guides = "collect")

Barplot

We make a barplot to compare IBL and ORS populations in HS vs HD samples. The proportion of IBL is indicated on top of bars.

quantif = table(sobj$sample_identifier,
                sobj$cluster_type) %>%
  as.data.frame.table() %>%
  `colnames<-`(c("Sample", "cell_type", "nb_cells")) %>%
  dplyr::group_by(Sample) %>%
  dplyr::mutate(total_cells = sum(nb_cells)) %>%
  as.data.frame() %>%
  dplyr::filter(cell_type == "IBL") %>%
  dplyr::mutate(prop_ibl = nb_cells / total_cells) %>%
  dplyr::mutate(prop_ibl = 100*round(prop_ibl, 4))

sobj$seurat_clusters = factor(sobj$seurat_clusters,
                              levels = names(sort(cell_type_clusters)))

aquarius::plot_barplot(df = table(sobj$sample_identifier,
                                  sobj$seurat_clusters) %>%
                         as.data.frame.table() %>%
                         `colnames<-`(c("sample_identifier", "clusters", "nb_cells")),
                       x = "sample_identifier", y = "nb_cells", fill = "clusters",
                       position = position_fill()) +
  ggplot2::scale_fill_manual(values = c(colorRampPalette(c("chartreuse1", "chartreuse4"))(table(sort(cell_type_clusters))["IBL"]),
                                        colorRampPalette(c("cadetblue1", "cadetblue4"))(table(sort(cell_type_clusters))["ORS"])),
                             breaks = names(sort(cell_type_clusters)),
                             name = "Cell type") +
  ggplot2::geom_label(data = quantif, inherit.aes = FALSE,
                      aes(x = .data$Sample, y = 1.05, label = .data$prop_ibl),
                      label.size = 0, size = 5)

IBL vs ORS

In this section, we perform DE between inner bulge layer (IBL) and outer root sheath (ORS) populations.

Preparation

We save the results in a list :

list_results = list()

We make over-representation analysis for each group of genes. We load gene sets from MSigDB :

gene_sets = aquarius::get_gene_sets(species = "Homo sapiens")
gene_sets = gene_sets$gene_sets

head(gene_sets)
## # A tibble: 6 x 16
##   gs_cat gs_subcat gs_name gene_symbol entrez_gene ensembl_gene human_gene_symb~
##   <chr>  <chr>     <chr>   <chr>             <int> <chr>        <chr>           
## 1 C5     GO:BP     GOBP_1~ AASDHPPT          60496 ENSG0000014~ AASDHPPT        
## 2 C5     GO:BP     GOBP_1~ ALDH1L1           10840 ENSG0000014~ ALDH1L1         
## 3 C5     GO:BP     GOBP_1~ ALDH1L2          160428 ENSG0000013~ ALDH1L2         
## 4 C5     GO:BP     GOBP_1~ MTHFD1             4522 ENSG0000010~ MTHFD1          
## 5 C5     GO:BP     GOBP_1~ MTHFD1L           25902 ENSG0000012~ MTHFD1L         
## 6 C5     GO:BP     GOBP_1~ MTHFD2L          441024 ENSG0000016~ MTHFD2L         
## # ... with 9 more variables: human_entrez_gene <int>, human_ensembl_gene <chr>,
## #   gs_id <chr>, gs_pmid <chr>, gs_geoid <chr>, gs_exact_source <chr>,
## #   gs_url <chr>, gs_description <chr>, category <chr>

How many gene sets ?

gene_sets[, c("gs_subcat", "gs_name")] %>%
  dplyr::distinct() %>%
  dplyr::pull(gs_subcat) %>%
  table() %>%
  as.data.frame.table() %>%
  `colnames<-`(c("Category", "Nb gene sets"))
##          Category Nb gene sets
## 1                           50
## 2         CP:KEGG          186
## 3          CP:PID          196
## 4     CP:REACTOME         1615
## 5 CP:WIKIPATHWAYS          664
## 6           GO:BP         7658
## 7           GO:CC         1006
## 8           GO:MF         1738

We get gene name and gene ID correspondence :

gene_corresp = sobj@assays[["RNA"]]@meta.features[, c("gene_name", "Ensembl_ID")] %>%
  `colnames<-`(c("NAME", "ID")) %>%
  dplyr::mutate(ID = as.character(ID))
rownames(gene_corresp) = gene_corresp$ID

head(gene_corresp)
##                       NAME              ID
## ENSG00000238009 AL627309.1 ENSG00000238009
## ENSG00000237491 AL669831.5 ENSG00000237491
## ENSG00000225880  LINC00115 ENSG00000225880
## ENSG00000230368     FAM41C ENSG00000230368
## ENSG00000223764 AL645608.1 ENSG00000223764
## ENSG00000187634     SAMD11 ENSG00000187634

Set idents

group_name = "IBL_vs_ORS"

We change cell identities to cluster type :

Seurat::Idents(sobj) = sobj$cluster_type

table(Seurat::Idents(sobj))
## 
##  IBL  ORS 
## 6774 1252

DE

We identify specific markers for each population :

mark = Seurat::FindMarkers(sobj, ident.1 = "IBL", ident.2 = "ORS")

mark = mark %>%
  dplyr::filter(p_val_adj < 0.05) %>%
  dplyr::arrange(-avg_logFC, pct.1 - pct.2)

list_results[[group_name]]$mark = mark

dim(mark)
## [1] 910   5
head(mark, n = 20)
##                p_val avg_logFC pct.1 pct.2     p_val_adj
## KRT16   0.000000e+00  3.839028 0.995 0.613  0.000000e+00
## FABP5   0.000000e+00  3.332035 0.995 0.637  0.000000e+00
## KRT6B   0.000000e+00  2.889195 0.986 0.538  0.000000e+00
## KRT6C   0.000000e+00  2.834859 0.924 0.148  0.000000e+00
## KRT6A   0.000000e+00  2.745803 0.914 0.521  0.000000e+00
## KRT17   0.000000e+00  2.105738 0.995 0.890  0.000000e+00
## CST6   1.369805e-101  1.988074 0.948 0.897  2.128813e-97
## GJA1    0.000000e+00  1.958676 0.955 0.459  0.000000e+00
## SDC1    0.000000e+00  1.882681 0.934 0.523  0.000000e+00
## S100A1  0.000000e+00  1.870696 0.682 0.073  0.000000e+00
## LYPD3   0.000000e+00  1.833088 0.868 0.236  0.000000e+00
## SBSN   1.249066e-249  1.614877 0.784 0.375 1.941174e-245
## MUCL1   1.098454e-12  1.595093 0.106 0.042  1.707107e-08
## CALML3  0.000000e+00  1.581308 0.995 0.897  0.000000e+00
## CRABP2  0.000000e+00  1.558322 0.735 0.107  0.000000e+00
## GJB6    0.000000e+00  1.534130 0.890 0.550  0.000000e+00
## CALML5 9.419204e-120  1.499714 0.696 0.418 1.463838e-115
## S100A2  0.000000e+00  1.415763 0.990 0.992  0.000000e+00
## PDZRN3  0.000000e+00  1.410214 0.677 0.042  0.000000e+00
## DSP     0.000000e+00  1.382991 0.958 0.810  0.000000e+00

There are 910 genes differentially expressed. How many for each population ?

# IBL
mark_ibl = mark %>%
  dplyr::filter(avg_logFC > 0)
nrow(mark_ibl)
## [1] 493
# ORS
mark_ors = mark %>%
  dplyr::filter(avg_logFC < 0)
nrow(mark_ors)
## [1] 417

We represent the information on a figure :

mark$gene_name = rownames(mark)
mark_to_label = rbind(
  # up-regulated in IBL
  mark %>% dplyr::top_n(., n = 20, wt = avg_logFC),
  # up-regulated in ORS
  mark %>% dplyr::top_n(., n = 20, wt = -avg_logFC),
  # representative and selective for IBL
  mark %>% dplyr::top_n(., n = 20, wt = (pct.1 - pct.2)),
  # representative and selective for ORS
  mark %>% dplyr::top_n(., n = 20, wt = -(pct.1 - pct.2))) %>%
  dplyr::distinct()

ggplot2::ggplot(mark, aes(x = pct.1, y = pct.2, col = avg_logFC)) +
  ggplot2::geom_abline(slope = 1, intercept = 0, lty = 2) +
  ggplot2::geom_point() +
  ggrepel::geom_label_repel(data = mark_to_label, max.overlaps = Inf,
                            aes(x = pct.1, y = pct.2, label = gene_name),
                            col = "black", fill = NA, size = 3, label.size = NA) +
  ggplot2::labs(title = "Differentially expressed genes",
                subtitle = "between IBL and ORS") +
  ggplot2::scale_color_gradient2(low = aquarius::color_cnv[1],
                                 mid = aquarius::color_cnv[2],
                                 high = aquarius::color_cnv[3],
                                 midpoint = 0) +
  ggplot2::theme_classic() +
  ggplot2::theme(plot.title = element_text(hjust = 0.5),
                 plot.subtitle = element_text(hjust = 0.5))

IBL

We explore enrichment in gene sets for IBL population

genes_of_interest = rownames(mark_ibl)

enrichr_results = aquarius::run_enrichr(gene_names = genes_of_interest,
                                        gene_corresp = gene_corresp,
                                        gene_sets = gene_sets[, c("gs_name", "ensembl_gene")],
                                        make_plot = TRUE,
                                        plot_title = "Up-regulated in IBL compared to ORS")

list_results[[group_name]]$enrichr_ibl = enrichr_results$ego

enrichr_results$plot +
  ggplot2::theme(axis.text.y = element_text(size = 8))

ORS

We explore enrichment in gene sets for ORS population.

genes_of_interest = rownames(mark_ors)

enrichr_results = aquarius::run_enrichr(gene_names = genes_of_interest,
                                        gene_corresp = gene_corresp,
                                        gene_sets = gene_sets[, c("gs_name", "ensembl_gene")],
                                        make_plot = TRUE,
                                        plot_title = "Up-regulated in ORS compared to IBL")

list_results[[group_name]]$enrichr_ors = enrichr_results$ego

enrichr_results$plot +
  ggplot2::theme(axis.text.y = element_text(size = 8))

GSEA

We run a GSEA for all gene sets, from the full count matrix :

ranked_gene_list = aquarius::run_foldchange(Seurat::GetAssayData(sobj, assay = "RNA", slot = "counts"),
                                            group1 = colnames(sobj)[sobj@active.ident %in% "IBL"],
                                            group2 = colnames(sobj)[sobj@active.ident %in% "ORS"])
names(ranked_gene_list) = gene_corresp$ID

gsea_results = aquarius::gsea_run(ranked_gene_list = ranked_gene_list,
                                  gene_sets = gene_sets[, c("gs_name", "ensembl_gene")],
                                  GSEA_p_val_thresh = 1)

list_results[[group_name]]$gsea = gsea_results

gsea_results@result %>%
  dplyr::filter(pvalue < 0.05) %>%
  dplyr::top_n(., n = 200, wt = abs(NES)) %>%
  dplyr::mutate(too_long = ifelse(nchar(ID) > 60, yes = TRUE, no = FALSE)) %>%
  dplyr::mutate(ID = stringr::str_sub(ID, end = 60)) %>%
  dplyr::mutate(ID = ifelse(too_long, yes = paste0(ID, "..."), no = ID)) %>%
  aquarius::gsea_plot(show_legend = TRUE) +
  ggplot2::labs(title = "GSEA using all genes (count matrix)") +
  ggplot2::theme(plot.title = element_text(size = 20))

We make the gsea plot for two gene sets :

p1 = enrichplot::gseaplot2(x = gsea_results, geneSetID = "REACTOME_KERATINIZATION") +
  ggplot2::labs(title = "REACTOME_KERATINIZATION") +
  ggplot2::theme(plot.title = element_text(hjust = 0.5, face = "bold",
                                           margin = ggplot2::margin(3, 3, 5, 3)))

p2 = enrichplot::gseaplot2(x = gsea_results, geneSetID = "HALLMARK_INTERFERON_GAMMA_RESPONSE") +
  ggplot2::labs(title = "HALLMARK_INTERFERON_GAMMA_RESPONSE") +
  ggplot2::theme(plot.title = element_text(hjust = 0.5, face = "bold",
                                           margin = ggplot2::margin(3, 3, 5, 3)))

p1 | p2

Save

We save the list of results :

saveRDS(list_results, file = paste0(out_dir, "/", save_name, "_list_results.rds"))

R Session

show
## R version 3.6.3 (2020-02-29)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 20.04.6 LTS
## 
## Matrix products: default
## BLAS:   /usr/local/lib/R/lib/libRblas.so
## LAPACK: /usr/local/lib/R/lib/libRlapack.so
## 
## locale:
## [1] C
## 
## attached base packages:
##  [1] parallel  stats4    grid      stats     graphics  grDevices utils    
##  [8] datasets  methods   base     
## 
## other attached packages:
##  [1] org.Mm.eg.db_3.10.0   AnnotationDbi_1.48.0  IRanges_2.20.2       
##  [4] S4Vectors_0.24.4      Biobase_2.46.0        BiocGenerics_0.32.0  
##  [7] ComplexHeatmap_2.14.0 ggplot2_3.3.5         patchwork_1.1.2      
## [10] dplyr_1.0.7          
## 
## loaded via a namespace (and not attached):
##   [1] softImpute_1.4              graphlayouts_0.7.0         
##   [3] pbapply_1.4-2               lattice_0.20-41            
##   [5] haven_2.3.1                 vctrs_0.3.8                
##   [7] usethis_2.0.1               dynwrap_1.2.1              
##   [9] blob_1.2.1                  survival_3.2-13            
##  [11] prodlim_2019.11.13          dynutils_1.0.5             
##  [13] later_1.3.0                 DBI_1.1.1                  
##  [15] R.utils_2.11.0              SingleCellExperiment_1.8.0 
##  [17] rappdirs_0.3.3              uwot_0.1.8                 
##  [19] dqrng_0.2.1                 jpeg_0.1-8.1               
##  [21] zlibbioc_1.32.0             pspline_1.0-18             
##  [23] pcaMethods_1.78.0           mvtnorm_1.1-1              
##  [25] htmlwidgets_1.5.4           GlobalOptions_0.1.2        
##  [27] future_1.22.1               UpSetR_1.4.0               
##  [29] laeken_0.5.2                leiden_0.3.3               
##  [31] clustree_0.4.3              scater_1.14.6              
##  [33] irlba_2.3.3                 DEoptimR_1.0-9             
##  [35] tidygraph_1.1.2             Rcpp_1.0.9                 
##  [37] readr_2.0.2                 KernSmooth_2.23-17         
##  [39] carrier_0.1.0               promises_1.1.0             
##  [41] gdata_2.18.0                DelayedArray_0.12.3        
##  [43] limma_3.42.2                graph_1.64.0               
##  [45] RcppParallel_5.1.4          Hmisc_4.4-0                
##  [47] fs_1.5.2                    RSpectra_0.16-0            
##  [49] fastmatch_1.1-0             ranger_0.12.1              
##  [51] digest_0.6.25               png_0.1-7                  
##  [53] sctransform_0.2.1           cowplot_1.0.0              
##  [55] DOSE_3.12.0                 here_1.0.1                 
##  [57] TInGa_0.0.0.9000            ggraph_2.0.3               
##  [59] pkgconfig_2.0.3             GO.db_3.10.0               
##  [61] DelayedMatrixStats_1.8.0    gower_0.2.1                
##  [63] ggbeeswarm_0.6.0            iterators_1.0.12           
##  [65] DropletUtils_1.6.1          reticulate_1.26            
##  [67] clusterProfiler_3.14.3      SummarizedExperiment_1.16.1
##  [69] circlize_0.4.15             beeswarm_0.4.0             
##  [71] GetoptLong_1.0.5            xfun_0.35                  
##  [73] bslib_0.3.1                 zoo_1.8-10                 
##  [75] tidyselect_1.1.0            reshape2_1.4.4             
##  [77] purrr_0.3.4                 ica_1.0-2                  
##  [79] pcaPP_1.9-73                viridisLite_0.3.0          
##  [81] rtracklayer_1.46.0          rlang_1.0.2                
##  [83] hexbin_1.28.1               jquerylib_0.1.4            
##  [85] dyneval_0.9.9               glue_1.4.2                 
##  [87] RColorBrewer_1.1-2          matrixStats_0.56.0         
##  [89] stringr_1.4.0               lava_1.6.7                 
##  [91] europepmc_0.3               DESeq2_1.26.0              
##  [93] recipes_0.1.17              labeling_0.3               
##  [95] httpuv_1.5.2                class_7.3-17               
##  [97] BiocNeighbors_1.4.2         DO.db_2.9                  
##  [99] annotate_1.64.0             jsonlite_1.7.2             
## [101] XVector_0.26.0              bit_4.0.4                  
## [103] mime_0.9                    aquarius_0.1.5             
## [105] Rsamtools_2.2.3             gridExtra_2.3              
## [107] gplots_3.0.3                stringi_1.4.6              
## [109] processx_3.5.2              gsl_2.1-6                  
## [111] bitops_1.0-6                cli_3.0.1                  
## [113] batchelor_1.2.4             RSQLite_2.2.0              
## [115] randomForest_4.6-14         tidyr_1.1.4                
## [117] data.table_1.14.2           rstudioapi_0.13            
## [119] GenomicAlignments_1.22.1    nlme_3.1-147               
## [121] qvalue_2.18.0               scran_1.14.6               
## [123] locfit_1.5-9.4              scDblFinder_1.1.8          
## [125] listenv_0.8.0               ggthemes_4.2.4             
## [127] gridGraphics_0.5-0          R.oo_1.24.0                
## [129] dbplyr_1.4.4                TTR_0.24.2                 
## [131] readxl_1.3.1                lifecycle_1.0.1            
## [133] timeDate_3043.102           ggpattern_0.3.1            
## [135] munsell_0.5.0               cellranger_1.1.0           
## [137] R.methodsS3_1.8.1           proxyC_0.1.5               
## [139] visNetwork_2.0.9            caTools_1.18.0             
## [141] codetools_0.2-16            GenomeInfoDb_1.22.1        
## [143] vipor_0.4.5                 lmtest_0.9-38              
## [145] msigdbr_7.5.1               htmlTable_1.13.3           
## [147] triebeard_0.3.0             lsei_1.2-0                 
## [149] xtable_1.8-4                ROCR_1.0-7                 
## [151] BiocManager_1.30.10         scatterplot3d_0.3-41       
## [153] abind_1.4-5                 farver_2.0.3               
## [155] parallelly_1.28.1           RANN_2.6.1                 
## [157] askpass_1.1                 GenomicRanges_1.38.0       
## [159] RcppAnnoy_0.0.16            tibble_3.1.5               
## [161] ggdendro_0.1-20             cluster_2.1.0              
## [163] future.apply_1.5.0          Seurat_3.1.5               
## [165] dendextend_1.15.1           Matrix_1.3-2               
## [167] ellipsis_0.3.2              prettyunits_1.1.1          
## [169] lubridate_1.7.9             ggridges_0.5.2             
## [171] igraph_1.2.5                RcppEigen_0.3.3.7.0        
## [173] fgsea_1.12.0                remotes_2.4.2              
## [175] scBFA_1.0.0                 destiny_3.0.1              
## [177] VIM_6.1.1                   testthat_3.1.0             
## [179] htmltools_0.5.2             BiocFileCache_1.10.2       
## [181] yaml_2.2.1                  utf8_1.1.4                 
## [183] plotly_4.9.2.1              XML_3.99-0.3               
## [185] ModelMetrics_1.2.2.2        e1071_1.7-3                
## [187] foreign_0.8-76              withr_2.5.0                
## [189] fitdistrplus_1.0-14         BiocParallel_1.20.1        
## [191] xgboost_1.4.1.1             bit64_4.0.5                
## [193] foreach_1.5.0               robustbase_0.93-9          
## [195] Biostrings_2.54.0           GOSemSim_2.13.1            
## [197] rsvd_1.0.3                  memoise_2.0.0              
## [199] evaluate_0.18               forcats_0.5.0              
## [201] rio_0.5.16                  geneplotter_1.64.0         
## [203] tzdb_0.1.2                  caret_6.0-86               
## [205] ps_1.6.0                    DiagrammeR_1.0.6.1         
## [207] curl_4.3                    fdrtool_1.2.15             
## [209] fansi_0.4.1                 highr_0.8                  
## [211] urltools_1.7.3              xts_0.12.1                 
## [213] GSEABase_1.48.0             acepack_1.4.1              
## [215] edgeR_3.28.1                checkmate_2.0.0            
## [217] scds_1.2.0                  cachem_1.0.6               
## [219] npsurv_0.4-0                babelgene_22.3             
## [221] rjson_0.2.20                openxlsx_4.1.5             
## [223] ggrepel_0.9.1               clue_0.3-60                
## [225] rprojroot_2.0.2             stabledist_0.7-1           
## [227] tools_3.6.3                 sass_0.4.0                 
## [229] nichenetr_1.1.1             magrittr_2.0.1             
## [231] RCurl_1.98-1.2              proxy_0.4-24               
## [233] car_3.0-11                  ape_5.3                    
## [235] ggplotify_0.0.5             xml2_1.3.2                 
## [237] httr_1.4.2                  assertthat_0.2.1           
## [239] rmarkdown_2.18              boot_1.3-25                
## [241] globals_0.14.0              R6_2.4.1                   
## [243] Rhdf5lib_1.8.0              nnet_7.3-14                
## [245] RcppHNSW_0.2.0              progress_1.2.2             
## [247] genefilter_1.68.0           statmod_1.4.34             
## [249] gtools_3.8.2                shape_1.4.6                
## [251] HDF5Array_1.14.4            BiocSingular_1.2.2         
## [253] rhdf5_2.30.1                splines_3.6.3              
## [255] AUCell_1.8.0                carData_3.0-4              
## [257] colorspace_1.4-1            generics_0.1.0             
## [259] base64enc_0.1-3             dynfeature_1.0.0           
## [261] smoother_1.1                gridtext_0.1.1             
## [263] pillar_1.6.3                tweenr_1.0.1               
## [265] sp_1.4-1                    ggplot.multistats_1.0.0    
## [267] rvcheck_0.1.8               GenomeInfoDbData_1.2.2     
## [269] plyr_1.8.6                  gtable_0.3.0               
## [271] zip_2.2.0                   knitr_1.41                 
## [273] latticeExtra_0.6-29         biomaRt_2.42.1             
## [275] fastmap_1.1.0               ADGofTest_0.3              
## [277] copula_1.0-0                doParallel_1.0.15          
## [279] vcd_1.4-8                   babelwhale_1.0.1           
## [281] openssl_1.4.1               scales_1.1.1               
## [283] backports_1.2.1             ipred_0.9-12               
## [285] enrichplot_1.6.1            hms_1.1.1                  
## [287] ggforce_0.3.1               Rtsne_0.15                 
## [289] shiny_1.7.1                 numDeriv_2016.8-1.1        
## [291] polyclip_1.10-0             lazyeval_0.2.2             
## [293] Formula_1.2-3               tsne_0.1-3                 
## [295] crayon_1.3.4                MASS_7.3-54                
## [297] pROC_1.16.2                 viridis_0.5.1              
## [299] dynparam_1.0.0              rpart_4.1-15               
## [301] zinbwave_1.8.0              compiler_3.6.3             
## [303] ggtext_0.1.0
LS0tCnRpdGxlOiAiT0VQMDAyMzIxIGRhdGFzZXQiCnN1YnRpdGxlOiAiTWFrZSBJQkwgKyBPUlMgYW5hbHlzaXMiCmF1dGhvcjogIkF1ZHJleSIKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJVktJW0tJWQnKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQotLS0KCjxzdHlsZT4KYm9keSB7CnRleHQtYWxpZ246IGp1c3RpZnl9Cjwvc3R5bGU+Cgo8IS0tIEF1dG9tYXRpY2FsbHkgY29tcHV0ZXMgYW5kIHByaW50cyBpbiB0aGUgb3V0cHV0IHRoZSBydW5uaW5nIHRpbWUgZm9yIGFueSBjb2RlIGNodW5rIC0tPgpgYGB7ciwgZWNobz1GQUxTRX0KIyBodHRwczovL2dpdGh1Yi5jb20vcnN0dWRpby9ybWFya2Rvd24vaXNzdWVzLzE0NTMKaG9va3MgPSBrbml0cjo6a25pdF9ob29rcyRnZXQoKQpob29rX2ZvbGRhYmxlID0gZnVuY3Rpb24odHlwZSkgewogIGZvcmNlKHR5cGUpCiAgZnVuY3Rpb24oeCwgb3B0aW9ucykgewogICAgcmVzID0gaG9va3NbW3R5cGVdXSh4LCBvcHRpb25zKQogICAgCiAgICBpZiAoaXNGQUxTRShvcHRpb25zW1twYXN0ZTAoImZvbGRfIiwgdHlwZSldXSkpIHJldHVybihyZXMpCiAgICAKICAgIHBhc3RlMCgKICAgICAgIjxkZXRhaWxzPjxzdW1tYXJ5PiIsICJzaG93IiwgIjwvc3VtbWFyeT5cblxuIiwKICAgICAgcmVzLAogICAgICAiXG5cbjwvZGV0YWlscz4iCiAgICApCiAgfQp9CmtuaXRyOjprbml0X2hvb2tzJHNldCgKICBvdXRwdXQgPSBob29rX2ZvbGRhYmxlKCJvdXRwdXQiKSwKICBwbG90ID0gaG9va19mb2xkYWJsZSgicGxvdCIpLAogIHRpbWVfaXQgPSBsb2NhbCh7CiAgICBub3cgPSBOVUxMCiAgICBmdW5jdGlvbihiZWZvcmUsIG9wdGlvbnMpIHsKICAgICAgaWYgKG9wdGlvbnMkdGltZV9pdCkgewogICAgICAgIGlmIChiZWZvcmUpIHsKICAgICAgICAgIG5vdyA8PSBTeXMudGltZSgpCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHJlcyA9IGRpZmZ0aW1lKFN5cy50aW1lKCksIG5vdywgdW5pdHMgPSAic2VjcyIpCiAgICAgICAgICBwYXN0ZSgiKFRpbWUgdG8gcnVuIDoiLCByb3VuZChyZXMsIGRpZ2l0cyA9IDIpLCAicykiKQogICAgICAgIH0KICAgICAgfQogICAgfQogIH0pCikKYGBgCgo8IS0tIFNldCBkZWZhdWx0IHBhcmFtZXRlcnMgZm9yIGFsbCBjaHVua3MgLS0+CmBgYHtyLCBzZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQpzZXQuc2VlZCgxMzM3TCkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAjIGRpc3BsYXkgY29kZQogICAgICAgICAgICAgICAgICAgICAgIyBkaXNwbGF5IGNodW5rIG91dHB1dAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgZm9sZF9vdXRwdXQgPSBGQUxTRSwgIyB1c2VmdWxsIGZvciBzZXNzaW9uSW5mbygpCiAgICAgICAgICAgICAgICAgICAgICBmb2xkX3Bsb3QgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgIyBmaWd1cmUgc2V0dGluZ3MKICAgICAgICAgICAgICAgICAgICAgIGZpZy5hbGlnbiA9ICdjZW50ZXInLAogICAgICAgICAgICAgICAgICAgICAgZmlnLndpZHRoID0gMjAsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuaGVpZ2h0ID0gMTUsCiAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICMgc29tZXRoaW5nIGFib3V0IHNlZWQsIGNodW5rIGFuZCBSbWFya2Rvd24gY29tcGlsYXRpb24KICAgICAgICAgICAgICAgICAgICAgICMgaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMzk0MTcwMDMvbG9uZy12ZWN0b3JzLW5vdC1zdXBwb3J0ZWQteWV0LWVycm9yLWluLXJtZC1idXQtbm90LWluLXItc2NyaXB0CiAgICAgICAgICAgICAgICAgICAgICAjIGNhY2hlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIGNhY2hlLmxhenkgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICMgYWRkIHJ1bnRpbWUgYWZ0ZXIgY2h1bmsKICAgICAgICAgICAgICAgICAgICAgIHRpbWVfaXQgPSBGQUxTRSkKYGBgCgoKVGhpcyBmaWxlIGlzIHVzZWQgdG8gYW5hbHlzZSB0aGUgaW1tdW5lIGNlbGxzIGRhdGFzZXQuCgpgYGB7ciBsaWJyYXJ5fQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQpsaWJyYXJ5KG9yZy5NbS5lZy5kYikKCi5saWJQYXRocygpCmBgYAoKIyBQcmVwYXJhdGlvbgoKSW4gdGhpcyBzZWN0aW9uLCB3ZSBzZXQgdGhlIGdsb2JhbCBzZXR0aW5ncyBvZiB0aGUgYW5hbHlzaXMuIFdlIHdpbGwgc3RvcmUgZGF0YSB0aGVyZSA6CgpgYGB7ciBvdXRfZGlyfQpzYXZlX25hbWUgPSAiaWJsbW9ycyIKb3V0X2RpciA9ICIuIgpgYGAKCldlIGxvYWQgdGhlIGRhdGFzZXQgOgoKYGBge3IgbG9hZF9zb2JqfQpzb2JqID0gcmVhZFJEUyhwYXN0ZTAob3V0X2RpciwgIi8iLCBzYXZlX25hbWUsICJfc29iai5yZHMiKSkKc29iagpgYGAKCldlIGxvYWQgdGhlIHNhbXBsZSBpbmZvcm1hdGlvbiA6CgpgYGB7ciBjdXN0b21fcGFsZXR0ZV9zYW1wbGUsIGZpZy53aWR0aCA9IDYsIGZpZy5oZWlnaHQgPSA2fQpzYW1wbGVfaW5mbyA9IHJlYWRSRFMocGFzdGUwKG91dF9kaXIsICIvLi4vMV9tZXRhZGF0YS93dV9zYW1wbGVfaW5mby5yZHMiKSkKcHJvamVjdF9uYW1lc19vaSA9IHNhbXBsZV9pbmZvJHByb2plY3RfbmFtZQoKZ3JhcGhpY3M6OnBpZShyZXAoMSwgbnJvdyhzYW1wbGVfaW5mbykpLAogICAgICAgICAgICAgIGNvbCA9IHNhbXBsZV9pbmZvJGNvbG9yLAogICAgICAgICAgICAgIGxhYmVscyA9IHNhbXBsZV9pbmZvJHByb2plY3RfbmFtZSkKYGBgCgpIZXJlIGFyZSBjdXN0b20gY29sb3JzIGZvciBlYWNoIGNlbGwgdHlwZSA6CgpgYGB7ciBjb2xvcl9tYXJrZXJzLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDEsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpjb2xvcl9tYXJrZXJzID0gcmVhZFJEUyhwYXN0ZTAob3V0X2RpciwgIi8uLi8uLi8xX21ldGFkYXRhL2hzX2hkX2NvbG9yX21hcmtlcnMucmRzIikpCgpkYXRhLmZyYW1lKGNlbGxfdHlwZSA9IG5hbWVzKGNvbG9yX21hcmtlcnMpLAogICAgICAgICAgIGNvbG9yID0gdW5saXN0KGNvbG9yX21hcmtlcnMpKSAlPiUKICBnZ3Bsb3QyOjpnZ3Bsb3QoLiwgYWVzKHggPSBjZWxsX3R5cGUsIHkgPSAwLCBmaWxsID0gY2VsbF90eXBlKSkgKwogIGdncGxvdDI6Omdlb21fcG9pbnQocGNoID0gMjEsIHNpemUgPSA1KSArCiAgZ2dwbG90Mjo6c2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gdW5saXN0KGNvbG9yX21hcmtlcnMpLCBicmVha3MgPSBuYW1lcyhjb2xvcl9tYXJrZXJzKSkgKwogIGdncGxvdDI6OnRoZW1lX2NsYXNzaWMoKSArCiAgZ2dwbG90Mjo6dGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgaGp1c3QgPSAxKSkKYGBgCgpUaGlzIGlzIHRoZSBwcm9qZWN0aW9uIG9mIGludGVyZXN0IDoKCmBgYHtyIG5hbWUyRH0KbmFtZTJEID0gImhhcm1vbnlfMjBfdHNuZSIKYGBgCgpXZSBkZXNpZ24gYSBjdXN0b20gZnVuY3Rpb24gdG8gbWFrZSB0aGUgR1NFQSBwbG90IGFuZCBhIHdvcmQgY2xvdWQgZ3JhcGggOgoKYGBge3IgbWFrZV9nc2VhX3Bsb3QsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQptYWtlX2dzZWFfcGxvdCA9IGZ1bmN0aW9uKGdzZWFfcmVzdWx0cywgZ3Nfb2ksIGZvbGRfY2hhbmdlLCBtZXRyaWMgPSAiRkMiKSB7CiAgZm9sZF9jaGFuZ2UkbWV0cmljID0gZm9sZF9jaGFuZ2VbLCBtZXRyaWNdCiAgCiAgcGxvdF9saXN0ID0gbGFwcGx5KGdzX29pLCBGVU4gPSBmdW5jdGlvbihnZW5lX3NldCkgewogICAgIyBHZW5lIHNldCBjb250ZW50CiAgICBnc19jb250ZW50ID0gZ2VuZV9zZXRzICU+JQogICAgICBkcGx5cjo6ZmlsdGVyKGdzX25hbWUgPT0gZ2VuZV9zZXQpICU+JQogICAgICBkcGx5cjo6cHVsbChlbnNlbWJsX2dlbmUpICU+JQogICAgICB1bmlxdWUoKQogICAgCiAgICAjIEdlbmUgc2V0IHNpemUKICAgIG5iX2dlbmVzID0gbGVuZ3RoKGdzX2NvbnRlbnQpCiAgICAKICAgICMgRW5yaWNobWVudCBtZXRyaWNzCiAgICBORVMgPSBnc2VhX3Jlc3VsdHNAcmVzdWx0W2dlbmVfc2V0LCAiTkVTIl0KICAgIHAuYWRqdXN0ID0gZ3NlYV9yZXN1bHRzQHJlc3VsdFtnZW5lX3NldCwgInAuYWRqdXN0Il0gJT4lCiAgICAgIHJvdW5kKC4sIDQpCiAgICBxdmFsdWVzID0gZ3NlYV9yZXN1bHRzQHJlc3VsdFtnZW5lX3NldCwgInF2YWx1ZXMiXQogICAgCiAgICBpZiAocC5hZGp1c3QgPiAwLjA1KSB7CiAgICAgIHAuYWRqdXN0ID0gcGFzdGUwKCI8c3BhbiBzdHlsZT0nY29sb3I6cmVkOyc+IiwgcC5hZGp1c3QsICI8L3NwYW4+IikKICAgIH0KICAgIAogICAgbXlfc3VidGl0bGUgPSBwYXN0ZTAoIlxuTkVTIDogIiwgcm91bmQoTkVTLCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICIgfCBwYWRqIDogIiwgcC5hZGp1c3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAiIHwgcXZhbCA6ICIsIHJvdW5kKHF2YWx1ZXMsIDQpLAogICAgICAgICAgICAgICAgICAgICAgICAgIiB8IHNldCBzaXplIDogIiwgbmJfZ2VuZXMsICIgZ2VuZXMiKQogICAgCiAgICAjIFNpemUgbGltaXRzCiAgICBsb3dlcl9GQyA9IG1pbihmb2xkX2NoYW5nZVtnc19jb250ZW50LCBdJG1ldHJpYywgbmEucm0gPSBUUlVFKQogICAgdXBwZXJfRkMgPSBtYXgoZm9sZF9jaGFuZ2VbZ3NfY29udGVudCwgXSRtZXRyaWMsIG5hLnJtID0gVFJVRSkKICAgIAogICAgIyBQbG90CiAgICBwID0gZW5yaWNocGxvdDo6Z3NlYXBsb3QyKHggPSBnc2VhX3Jlc3VsdHMsIGdlbmVTZXRJRCA9IGdlbmVfc2V0KSArCiAgICAgIGdncGxvdDI6OmxhYnModGl0bGUgPSBnZW5lX3NldCwKICAgICAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9IG15X3N1YnRpdGxlKSArCiAgICAgIGdncGxvdDI6OnRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFyZ2luID0gZ2dwbG90Mjo6bWFyZ2luKDMsIDMsIDUsIDMpKSwKICAgICAgICAgICAgICAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGdndGV4dDo6ZWxlbWVudF9tYXJrZG93bihoanVzdCA9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMTApKQogICAgCiAgICB3YyA9IGdncGxvdDI6OmdncGxvdChmb2xkX2NoYW5nZVtnc19jb250ZW50LCBdLAogICAgICAgICAgICAgICAgICAgICAgICAgYWVzKGxhYmVsID0gZ2VuZV9uYW1lLCBzaXplID0gYWJzKG1ldHJpYyksIGNvbG9yID0gbWV0cmljKSkgKwogICAgICBnZ3dvcmRjbG91ZDo6Z2VvbV90ZXh0X3dvcmRjbG91ZF9hcmVhKHNob3cubGVnZW5kID0gVFJVRSkgKwogICAgICBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9ncmFkaWVudDIoCiAgICAgICAgbmFtZSA9IG1ldHJpYywKICAgICAgICBsb3cgPSBhcXVhcml1czo6Y29sb3JfY252WzFdLAogICAgICAgIG1pZCA9ICJncmF5NzAiLCBtaWRwb2ludCA9IDAsCiAgICAgICAgaGlnaCA9IGFxdWFyaXVzOjpjb2xvcl9jbnZbM10pICsKICAgICAgZ2dwbG90Mjo6c2NhbGVfc2l6ZV9hcmVhKG1heF9zaXplID0gNykgKwogICAgICBnZ3Bsb3QyOjp0aGVtZV9taW5pbWFsKCkgKwogICAgICBnZ3Bsb3QyOjpndWlkZXMoc2l6ZSA9ICJub25lIikKICAgIAogICAgcmV0dXJuKGxpc3QocCwgd2MpKQogIH0pICU+JSB1bmxpc3QoLiwgcmVjdXJzaXZlID0gRkFMU0UpCiAgCiAgcmV0dXJuKHBsb3RfbGlzdCkKfQpgYGAKCgojIFZpc3VhbGl6YXRpb24KCiMjIEdlbmUgZXhwcmVzc2lvbgoKV2UgdmlzdWFsaXplIGdlbmUgZXhwcmVzc2lvbiBmb3Igc29tZSBtYXJrZXJzIDoKCmBgYHtyIHBsb3RfbGlzdF9mZWF0dXJlcywgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSA0fQpmZWF0dXJlcyA9IGMoInBlcmNlbnQubXQiLCAicGVyY2VudC5yYiIsICJuRmVhdHVyZV9STkEiKQoKcGxvdF9saXN0ID0gbGFwcGx5KGZlYXR1cmVzLCBGVU4gPSBmdW5jdGlvbihvbmVfZ2VuZSkgewogIFNldXJhdDo6RmVhdHVyZVBsb3Qoc29iaiwgZmVhdHVyZXMgPSBvbmVfZ2VuZSwKICAgICAgICAgICAgICAgICAgICAgIHJlZHVjdGlvbiA9IG5hbWUyRCkgKwogICAgZ2dwbG90Mjo6dGhlbWUoYXNwZWN0LnJhdGlvID0gMSkgKwogICAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IGFxdWFyaXVzOjpjb2xvcl9nZW5lKSArCiAgICBTZXVyYXQ6Ok5vQXhlcygpCn0pCgpwYXRjaHdvcms6OndyYXBfcGxvdHMocGxvdF9saXN0LCBuY29sID0gMykKYGBgCgojIyBDbHVzdGVycwoKV2UgdmlzdWFsaXplIGNsdXN0ZXJzIDoKCmBgYHtyIHNlZV9jbHVzdGVyaW5nLCBmaWcud2lkdGggPSA2LCBmaWcuaGVpZ2h0ID0gNH0KY2x1c3Rlcl9wbG90ID0gU2V1cmF0OjpEaW1QbG90KHNvYmosIHJlZHVjdGlvbiA9IG5hbWUyRCwgbGFiZWwgPSBUUlVFKSArCiAgU2V1cmF0OjpOb0F4ZXMoKSArCiAgZ2dwbG90Mjo6dGhlbWUoYXNwZWN0LnJhdGlvID0gMSkKY2x1c3Rlcl9wbG90CmBgYAoKIyMgQ2VsbCB0eXBlCgpXZSB2aXN1YWxpemUgY2VsbCB0eXBlIHNwbGl0IGJ5IHNhbXBsZSA6CgpgYGB7ciBwbG90X3NwbGl0X2RpbXJlZCwgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSA3fQpwbG90X2xpc3QgPSBhcXVhcml1czo6cGxvdF9zcGxpdF9kaW1yZWQoc29iaiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZHVjdGlvbiA9IG5hbWUyRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwbGl0X2J5ID0gInByb2plY3RfbmFtZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieSA9ICJjZWxsX3R5cGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BsaXRfY29sb3IgPSBzZXROYW1lcyhzYW1wbGVfaW5mbyRjb2xvciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm0gPSBzYW1wbGVfaW5mbyRwcm9qZWN0X25hbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfY29sb3IgPSBjb2xvcl9tYXJrZXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmdfcHRfc2l6ZSA9IDAuNSwgbWFpbl9wdF9zaXplID0gMC41KQoKcGxvdF9saXN0W1tsZW5ndGgocGxvdF9saXN0KSArIDFdXSA9IGNsdXN0ZXJfcGxvdAoKcGF0Y2h3b3JrOjp3cmFwX3Bsb3RzKHBsb3RfbGlzdCwgbmNvbCA9IDQpICYKICBTZXVyYXQ6Ok5vTGVnZW5kKCkKYGBgCgojIyBDbHVzdGVyIHR5cGUKCldlIHN1bW1hcml6ZSBtYWpvciBjZWxsIHR5cGUgYnkgY2x1c3RlciA6CgpgYGB7ciBjZWxsX3R5cGVfY2x1c3RlcnN9CmNlbGxfdHlwZV9jbHVzdGVycyA9IHNvYmpAbWV0YS5kYXRhWywgYygiY2VsbF90eXBlIiwgInNldXJhdF9jbHVzdGVycyIpXSAlPiUKICB0YWJsZSgpICU+JQogIHByb3AudGFibGUoLiwgbWFyZ2luID0gMikgJT4lCiAgYXBwbHkoLiwgMiwgd2hpY2gubWF4KQpjZWxsX3R5cGVfY2x1c3RlcnMgPSBzZXROYW1lcyhsZXZlbHMoc29iaiRjZWxsX3R5cGUpW2NlbGxfdHlwZV9jbHVzdGVyc10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5tID0gbmFtZXMoY2VsbF90eXBlX2NsdXN0ZXJzKSkKCmBgYAoKV2UgZGVmaW5lIGNsdXN0ZXIgdHlwZSA6CgpgYGB7ciB0YWJsZV9jbHVzdGVyX3R5cGV9CnNvYmokY2x1c3Rlcl90eXBlID0gY2VsbF90eXBlX2NsdXN0ZXJzW3NvYmokc2V1cmF0X2NsdXN0ZXJzXSAlPiUKICBhcy5mYWN0b3IoKQp0YWJsZShzb2JqJGNsdXN0ZXJfdHlwZSwgc29iaiRjZWxsX3R5cGUpCmBgYAoKV2Ugc3Vic2V0IGBjb2xvcl9tYXJrZXJzYCA6CgpgYGB7ciBzdWJzZXRfY29sb3JzfQpjb2xvcl9tYXJrZXJzID0gY29sb3JfbWFya2Vyc1tsZXZlbHMoc29iaiRjbHVzdGVyX3R5cGUpXQpgYGAKCgpXZSBjb21wYXJlIGNsdXN0ZXIgYW5ub3RhdGlvbiBhbmQgY2VsbCB0eXBlIGFubm90YXRpb24gOgoKYGBge3Igc2VlX2NsdXN0ZXJfdHlwZSwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA1fQpwMSA9IFNldXJhdDo6RGltUGxvdChzb2JqLCBncm91cC5ieSA9ICJjZWxsX3R5cGUiLAogICAgICAgICAgICAgICAgICAgICByZWR1Y3Rpb24gPSBuYW1lMkQsIGNvbHMgPSBjb2xvcl9tYXJrZXJzKSArCiAgZ2dwbG90Mjo6bGFicyh0aXRsZSA9ICJDZWxsIHR5cGUiKSArCiAgU2V1cmF0OjpOb0F4ZXMoKSArCiAgZ2dwbG90Mjo6dGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCnAyID0gU2V1cmF0OjpEaW1QbG90KHNvYmosIGdyb3VwLmJ5ID0gImNsdXN0ZXJfdHlwZSIsCiAgICAgICAgICAgICAgICAgICAgIHJlZHVjdGlvbiA9IG5hbWUyRCwgY29scyA9IGNvbG9yX21hcmtlcnMpICsKICBnZ3Bsb3QyOjpsYWJzKHRpdGxlID0gIkNsdXN0ZXIgdHlwZSIpICsKICBTZXVyYXQ6Ok5vQXhlcygpICsKICBnZ3Bsb3QyOjp0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKcGF0Y2h3b3JrOjp3cmFwX3Bsb3RzKHAxLCBwMiwgZ3VpZGVzID0gImNvbGxlY3QiKQpgYGAKCiMjIEJhcnBsb3QKCldlIG1ha2UgYSBiYXJwbG90IHRvIGNvbXBhcmUgSUJMIGFuZCBPUlMgcG9wdWxhdGlvbnMgaW4gSFMgdnMgSEQgc2FtcGxlcy4gVGhlIHByb3BvcnRpb24gb2YgSUJMIGlzIGluZGljYXRlZCBvbiB0b3Agb2YgYmFycy4KCmBgYHtyIGJhcnBsb3RfaWJsX29ycywgZmlnLndpZHRoID0gNywgZmlnLmhlaWdodCA9IDV9CnF1YW50aWYgPSB0YWJsZShzb2JqJHNhbXBsZV9pZGVudGlmaWVyLAogICAgICAgICAgICAgICAgc29iaiRjbHVzdGVyX3R5cGUpICU+JQogIGFzLmRhdGEuZnJhbWUudGFibGUoKSAlPiUKICBgY29sbmFtZXM8LWAoYygiU2FtcGxlIiwgImNlbGxfdHlwZSIsICJuYl9jZWxscyIpKSAlPiUKICBkcGx5cjo6Z3JvdXBfYnkoU2FtcGxlKSAlPiUKICBkcGx5cjo6bXV0YXRlKHRvdGFsX2NlbGxzID0gc3VtKG5iX2NlbGxzKSkgJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIGRwbHlyOjpmaWx0ZXIoY2VsbF90eXBlID09ICJJQkwiKSAlPiUKICBkcGx5cjo6bXV0YXRlKHByb3BfaWJsID0gbmJfY2VsbHMgLyB0b3RhbF9jZWxscykgJT4lCiAgZHBseXI6Om11dGF0ZShwcm9wX2libCA9IDEwMCpyb3VuZChwcm9wX2libCwgNCkpCgpzb2JqJHNldXJhdF9jbHVzdGVycyA9IGZhY3Rvcihzb2JqJHNldXJhdF9jbHVzdGVycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gbmFtZXMoc29ydChjZWxsX3R5cGVfY2x1c3RlcnMpKSkKCmFxdWFyaXVzOjpwbG90X2JhcnBsb3QoZGYgPSB0YWJsZShzb2JqJHNhbXBsZV9pZGVudGlmaWVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc29iaiRzZXVyYXRfY2x1c3RlcnMpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgYXMuZGF0YS5mcmFtZS50YWJsZSgpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgYGNvbG5hbWVzPC1gKGMoInNhbXBsZV9pZGVudGlmaWVyIiwgImNsdXN0ZXJzIiwgIm5iX2NlbGxzIikpLAogICAgICAgICAgICAgICAgICAgICAgIHggPSAic2FtcGxlX2lkZW50aWZpZXIiLCB5ID0gIm5iX2NlbGxzIiwgZmlsbCA9ICJjbHVzdGVycyIsCiAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9maWxsKCkpICsKICBnZ3Bsb3QyOjpzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKGNvbG9yUmFtcFBhbGV0dGUoYygiY2hhcnRyZXVzZTEiLCAiY2hhcnRyZXVzZTQiKSkodGFibGUoc29ydChjZWxsX3R5cGVfY2x1c3RlcnMpKVsiSUJMIl0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3JSYW1wUGFsZXR0ZShjKCJjYWRldGJsdWUxIiwgImNhZGV0Ymx1ZTQiKSkodGFibGUoc29ydChjZWxsX3R5cGVfY2x1c3RlcnMpKVsiT1JTIl0pKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBuYW1lcyhzb3J0KGNlbGxfdHlwZV9jbHVzdGVycykpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiQ2VsbCB0eXBlIikgKwogIGdncGxvdDI6Omdlb21fbGFiZWwoZGF0YSA9IHF1YW50aWYsIGluaGVyaXQuYWVzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IC5kYXRhJFNhbXBsZSwgeSA9IDEuMDUsIGxhYmVsID0gLmRhdGEkcHJvcF9pYmwpLAogICAgICAgICAgICAgICAgICAgICAgbGFiZWwuc2l6ZSA9IDAsIHNpemUgPSA1KQpgYGAKCiMgSUJMIHZzIE9SUwoKSW4gdGhpcyBzZWN0aW9uLCB3ZSBwZXJmb3JtIERFIGJldHdlZW4gaW5uZXIgYnVsZ2UgbGF5ZXIgKElCTCkgYW5kIG91dGVyIHJvb3Qgc2hlYXRoIChPUlMpIHBvcHVsYXRpb25zLgoKIyMgUHJlcGFyYXRpb24KCldlIHNhdmUgdGhlIHJlc3VsdHMgaW4gYSBsaXN0IDoKCmBgYHtyIGxpc3RfcmVzdWx0c30KbGlzdF9yZXN1bHRzID0gbGlzdCgpCmBgYAoKV2UgbWFrZSBvdmVyLXJlcHJlc2VudGF0aW9uIGFuYWx5c2lzIGZvciBlYWNoIGdyb3VwIG9mIGdlbmVzLiBXZSBsb2FkIGdlbmUgc2V0cyBmcm9tIE1TaWdEQiA6CgpgYGB7ciBnZW5lX3NldHN9CmdlbmVfc2V0cyA9IGFxdWFyaXVzOjpnZXRfZ2VuZV9zZXRzKHNwZWNpZXMgPSAiSG9tbyBzYXBpZW5zIikKZ2VuZV9zZXRzID0gZ2VuZV9zZXRzJGdlbmVfc2V0cwoKaGVhZChnZW5lX3NldHMpCmBgYAoKSG93IG1hbnkgZ2VuZSBzZXRzID8KCmBgYHtyIGNvdW50X2dlbmVfc2V0c30KZ2VuZV9zZXRzWywgYygiZ3Nfc3ViY2F0IiwgImdzX25hbWUiKV0gJT4lCiAgZHBseXI6OmRpc3RpbmN0KCkgJT4lCiAgZHBseXI6OnB1bGwoZ3Nfc3ViY2F0KSAlPiUKICB0YWJsZSgpICU+JQogIGFzLmRhdGEuZnJhbWUudGFibGUoKSAlPiUKICBgY29sbmFtZXM8LWAoYygiQ2F0ZWdvcnkiLCAiTmIgZ2VuZSBzZXRzIikpCmBgYAoKV2UgZ2V0IGdlbmUgbmFtZSBhbmQgZ2VuZSBJRCBjb3JyZXNwb25kZW5jZSA6CgpgYGB7ciBnZW5lX2NvcnJlc3B9CmdlbmVfY29ycmVzcCA9IHNvYmpAYXNzYXlzW1siUk5BIl1dQG1ldGEuZmVhdHVyZXNbLCBjKCJnZW5lX25hbWUiLCAiRW5zZW1ibF9JRCIpXSAlPiUKICBgY29sbmFtZXM8LWAoYygiTkFNRSIsICJJRCIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKElEID0gYXMuY2hhcmFjdGVyKElEKSkKcm93bmFtZXMoZ2VuZV9jb3JyZXNwKSA9IGdlbmVfY29ycmVzcCRJRAoKaGVhZChnZW5lX2NvcnJlc3ApCmBgYAoKCiMjIFNldCBpZGVudHMKCmBgYHtyIGdyb3VwX25hbWVfaWJsX29yc30KZ3JvdXBfbmFtZSA9ICJJQkxfdnNfT1JTIgpgYGAKCgpXZSBjaGFuZ2UgY2VsbCBpZGVudGl0aWVzIHRvIGNsdXN0ZXIgdHlwZSA6CgpgYGB7ciBpZGVudF9jbHVzdGVyX3R5cGV9ClNldXJhdDo6SWRlbnRzKHNvYmopID0gc29iaiRjbHVzdGVyX3R5cGUKCnRhYmxlKFNldXJhdDo6SWRlbnRzKHNvYmopKQpgYGAKCiMjIyBERQoKV2UgaWRlbnRpZnkgc3BlY2lmaWMgbWFya2VycyBmb3IgZWFjaCBwb3B1bGF0aW9uIDoKCmBgYHtyIGRlX2NsdXN0MCwgZmlnLndpZHRoID0gNSwgZmlnLmhlaWdodCA9IDV9Cm1hcmsgPSBTZXVyYXQ6OkZpbmRNYXJrZXJzKHNvYmosIGlkZW50LjEgPSAiSUJMIiwgaWRlbnQuMiA9ICJPUlMiKQoKbWFyayA9IG1hcmsgJT4lCiAgZHBseXI6OmZpbHRlcihwX3ZhbF9hZGogPCAwLjA1KSAlPiUKICBkcGx5cjo6YXJyYW5nZSgtYXZnX2xvZ0ZDLCBwY3QuMSAtIHBjdC4yKQoKbGlzdF9yZXN1bHRzW1tncm91cF9uYW1lXV0kbWFyayA9IG1hcmsKCmRpbShtYXJrKQpoZWFkKG1hcmssIG4gPSAyMCkKYGBgCgpUaGVyZSBhcmUgYHIgbnJvdyhtYXJrKWAgZ2VuZXMgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkLiBIb3cgbWFueSBmb3IgZWFjaCBwb3B1bGF0aW9uID8KCmBgYHtyIG1ha3JfYnlfcG9wfQojIElCTAptYXJrX2libCA9IG1hcmsgJT4lCiAgZHBseXI6OmZpbHRlcihhdmdfbG9nRkMgPiAwKQpucm93KG1hcmtfaWJsKQoKIyBPUlMKbWFya19vcnMgPSBtYXJrICU+JQogIGRwbHlyOjpmaWx0ZXIoYXZnX2xvZ0ZDIDwgMCkKbnJvdyhtYXJrX29ycykKYGBgCgpXZSByZXByZXNlbnQgdGhlIGluZm9ybWF0aW9uIG9uIGEgZmlndXJlIDoKCmBgYHtyIHBsb3RfZGVfcG9wLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDEwfQptYXJrJGdlbmVfbmFtZSA9IHJvd25hbWVzKG1hcmspCm1hcmtfdG9fbGFiZWwgPSByYmluZCgKICAjIHVwLXJlZ3VsYXRlZCBpbiBJQkwKICBtYXJrICU+JSBkcGx5cjo6dG9wX24oLiwgbiA9IDIwLCB3dCA9IGF2Z19sb2dGQyksCiAgIyB1cC1yZWd1bGF0ZWQgaW4gT1JTCiAgbWFyayAlPiUgZHBseXI6OnRvcF9uKC4sIG4gPSAyMCwgd3QgPSAtYXZnX2xvZ0ZDKSwKICAjIHJlcHJlc2VudGF0aXZlIGFuZCBzZWxlY3RpdmUgZm9yIElCTAogIG1hcmsgJT4lIGRwbHlyOjp0b3BfbiguLCBuID0gMjAsIHd0ID0gKHBjdC4xIC0gcGN0LjIpKSwKICAjIHJlcHJlc2VudGF0aXZlIGFuZCBzZWxlY3RpdmUgZm9yIE9SUwogIG1hcmsgJT4lIGRwbHlyOjp0b3BfbiguLCBuID0gMjAsIHd0ID0gLShwY3QuMSAtIHBjdC4yKSkpICU+JQogIGRwbHlyOjpkaXN0aW5jdCgpCgpnZ3Bsb3QyOjpnZ3Bsb3QobWFyaywgYWVzKHggPSBwY3QuMSwgeSA9IHBjdC4yLCBjb2wgPSBhdmdfbG9nRkMpKSArCiAgZ2dwbG90Mjo6Z2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBsdHkgPSAyKSArCiAgZ2dwbG90Mjo6Z2VvbV9wb2ludCgpICsKICBnZ3JlcGVsOjpnZW9tX2xhYmVsX3JlcGVsKGRhdGEgPSBtYXJrX3RvX2xhYmVsLCBtYXgub3ZlcmxhcHMgPSBJbmYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IHBjdC4xLCB5ID0gcGN0LjIsIGxhYmVsID0gZ2VuZV9uYW1lKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9ICJibGFjayIsIGZpbGwgPSBOQSwgc2l6ZSA9IDMsIGxhYmVsLnNpemUgPSBOQSkgKwogIGdncGxvdDI6OmxhYnModGl0bGUgPSAiRGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIiwKICAgICAgICAgICAgICAgIHN1YnRpdGxlID0gImJldHdlZW4gSUJMIGFuZCBPUlMiKSArCiAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9IGFxdWFyaXVzOjpjb2xvcl9jbnZbMV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pZCA9IGFxdWFyaXVzOjpjb2xvcl9jbnZbMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2ggPSBhcXVhcml1czo6Y29sb3JfY252WzNdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IDApICsKICBnZ3Bsb3QyOjp0aGVtZV9jbGFzc2ljKCkgKwogIGdncGxvdDI6OnRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQpgYGAKCiMjIyBJQkwKCldlIGV4cGxvcmUgZW5yaWNobWVudCBpbiBnZW5lIHNldHMgZm9yIElCTCBwb3B1bGF0aW9uCgpgYGB7ciBvcmFfaWJsLCBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDZ9CmdlbmVzX29mX2ludGVyZXN0ID0gcm93bmFtZXMobWFya19pYmwpCgplbnJpY2hyX3Jlc3VsdHMgPSBhcXVhcml1czo6cnVuX2VucmljaHIoZ2VuZV9uYW1lcyA9IGdlbmVzX29mX2ludGVyZXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9jb3JyZXNwID0gZ2VuZV9jb3JyZXNwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9zZXRzID0gZ2VuZV9zZXRzWywgYygiZ3NfbmFtZSIsICJlbnNlbWJsX2dlbmUiKV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYWtlX3Bsb3QgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF90aXRsZSA9ICJVcC1yZWd1bGF0ZWQgaW4gSUJMIGNvbXBhcmVkIHRvIE9SUyIpCgpsaXN0X3Jlc3VsdHNbW2dyb3VwX25hbWVdXSRlbnJpY2hyX2libCA9IGVucmljaHJfcmVzdWx0cyRlZ28KCmVucmljaHJfcmVzdWx0cyRwbG90ICsKICBnZ3Bsb3QyOjp0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpCmBgYAoKIyMjIE9SUwoKV2UgZXhwbG9yZSBlbnJpY2htZW50IGluIGdlbmUgc2V0cyBmb3IgT1JTIHBvcHVsYXRpb24uCgpgYGB7ciBvcmFfb3JzLCBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDZ9CmdlbmVzX29mX2ludGVyZXN0ID0gcm93bmFtZXMobWFya19vcnMpCgplbnJpY2hyX3Jlc3VsdHMgPSBhcXVhcml1czo6cnVuX2VucmljaHIoZ2VuZV9uYW1lcyA9IGdlbmVzX29mX2ludGVyZXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9jb3JyZXNwID0gZ2VuZV9jb3JyZXNwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9zZXRzID0gZ2VuZV9zZXRzWywgYygiZ3NfbmFtZSIsICJlbnNlbWJsX2dlbmUiKV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYWtlX3Bsb3QgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF90aXRsZSA9ICJVcC1yZWd1bGF0ZWQgaW4gT1JTIGNvbXBhcmVkIHRvIElCTCIpCgpsaXN0X3Jlc3VsdHNbW2dyb3VwX25hbWVdXSRlbnJpY2hyX29ycyA9IGVucmljaHJfcmVzdWx0cyRlZ28KCmVucmljaHJfcmVzdWx0cyRwbG90ICsKICBnZ3Bsb3QyOjp0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpCmBgYAoKCiMjIyBHU0VBCgpXZSBydW4gYSBHU0VBIGZvciBhbGwgZ2VuZSBzZXRzLCBmcm9tIHRoZSBmdWxsIGNvdW50IG1hdHJpeCA6CgpgYGB7ciBnc2VhX2libF9vcnMsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gNDB9CnJhbmtlZF9nZW5lX2xpc3QgPSBhcXVhcml1czo6cnVuX2ZvbGRjaGFuZ2UoU2V1cmF0OjpHZXRBc3NheURhdGEoc29iaiwgYXNzYXkgPSAiUk5BIiwgc2xvdCA9ICJjb3VudHMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cDEgPSBjb2xuYW1lcyhzb2JqKVtzb2JqQGFjdGl2ZS5pZGVudCAlaW4lICJJQkwiXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cDIgPSBjb2xuYW1lcyhzb2JqKVtzb2JqQGFjdGl2ZS5pZGVudCAlaW4lICJPUlMiXSkKbmFtZXMocmFua2VkX2dlbmVfbGlzdCkgPSBnZW5lX2NvcnJlc3AkSUQKCmdzZWFfcmVzdWx0cyA9IGFxdWFyaXVzOjpnc2VhX3J1bihyYW5rZWRfZ2VuZV9saXN0ID0gcmFua2VkX2dlbmVfbGlzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfc2V0cyA9IGdlbmVfc2V0c1ssIGMoImdzX25hbWUiLCAiZW5zZW1ibF9nZW5lIildLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgR1NFQV9wX3ZhbF90aHJlc2ggPSAxKQoKbGlzdF9yZXN1bHRzW1tncm91cF9uYW1lXV0kZ3NlYSA9IGdzZWFfcmVzdWx0cwoKZ3NlYV9yZXN1bHRzQHJlc3VsdCAlPiUKICBkcGx5cjo6ZmlsdGVyKHB2YWx1ZSA8IDAuMDUpICU+JQogIGRwbHlyOjp0b3BfbiguLCBuID0gMjAwLCB3dCA9IGFicyhORVMpKSAlPiUKICBkcGx5cjo6bXV0YXRlKHRvb19sb25nID0gaWZlbHNlKG5jaGFyKElEKSA+IDYwLCB5ZXMgPSBUUlVFLCBubyA9IEZBTFNFKSkgJT4lCiAgZHBseXI6Om11dGF0ZShJRCA9IHN0cmluZ3I6OnN0cl9zdWIoSUQsIGVuZCA9IDYwKSkgJT4lCiAgZHBseXI6Om11dGF0ZShJRCA9IGlmZWxzZSh0b29fbG9uZywgeWVzID0gcGFzdGUwKElELCAiLi4uIiksIG5vID0gSUQpKSAlPiUKICBhcXVhcml1czo6Z3NlYV9wbG90KHNob3dfbGVnZW5kID0gVFJVRSkgKwogIGdncGxvdDI6OmxhYnModGl0bGUgPSAiR1NFQSB1c2luZyBhbGwgZ2VuZXMgKGNvdW50IG1hdHJpeCkiKSArCiAgZ2dwbG90Mjo6dGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApKQpgYGAKCldlIG1ha2UgdGhlIGdzZWEgcGxvdCBmb3IgdHdvIGdlbmUgc2V0cyA6CgpgYGB7ciBnc2VhX3Bsb3RfaWJsX29ycywgZmlnLndpZHRoID0gMTUsIGZpZy5oZWlnaHQgPSA3fQpwMSA9IGVucmljaHBsb3Q6OmdzZWFwbG90Mih4ID0gZ3NlYV9yZXN1bHRzLCBnZW5lU2V0SUQgPSAiUkVBQ1RPTUVfS0VSQVRJTklaQVRJT04iKSArCiAgZ2dwbG90Mjo6bGFicyh0aXRsZSA9ICJSRUFDVE9NRV9LRVJBVElOSVpBVElPTiIpICsKICBnZ3Bsb3QyOjp0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFyZ2luID0gZ2dwbG90Mjo6bWFyZ2luKDMsIDMsIDUsIDMpKSkKCnAyID0gZW5yaWNocGxvdDo6Z3NlYXBsb3QyKHggPSBnc2VhX3Jlc3VsdHMsIGdlbmVTZXRJRCA9ICJIQUxMTUFSS19JTlRFUkZFUk9OX0dBTU1BX1JFU1BPTlNFIikgKwogIGdncGxvdDI6OmxhYnModGl0bGUgPSAiSEFMTE1BUktfSU5URVJGRVJPTl9HQU1NQV9SRVNQT05TRSIpICsKICBnZ3Bsb3QyOjp0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFyZ2luID0gZ2dwbG90Mjo6bWFyZ2luKDMsIDMsIDUsIDMpKSkKCnAxIHwgcDIKYGBgCgoKIyBTYXZlCgpXZSBzYXZlIHRoZSBsaXN0IG9mIHJlc3VsdHMgOgoKYGBge3Igc2F2ZV9saXN0X3Jlc3VsdHN9CnNhdmVSRFMobGlzdF9yZXN1bHRzLCBmaWxlID0gcGFzdGUwKG91dF9kaXIsICIvIiwgc2F2ZV9uYW1lLCAiX2xpc3RfcmVzdWx0cy5yZHMiKSkKYGBgCgoKIyBSIFNlc3Npb24KCmBgYHtyIHNlc3Npb25pbmZvLCBlY2hvID0gRkFMU0UsIGZvbGRfb3V0cHV0ID0gVFJVRX0Kc2Vzc2lvbkluZm8oKQpgYGAKCg==